package com.ndood.admin.core.web.tools;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateBucketRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.StorageClass;
import com.ndood.admin.core.properties.AdminProperties;
import com.ndood.common.base.util.DateUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 依赖注解的图片上传工具类
 */
@Component
@Scope("prototype")
@Slf4j
public class FileUploadUtils {

	@Autowired
	private AdminProperties adminProperties;
	
	/**
	 * 通过文件名判断并获取OSS服务文件上传时文件的contentType
	 */
	public String getContentType(String fileName) {
		// 文件的后缀名
		String fileExtension = fileName.substring(fileName.lastIndexOf("."));
		if (".bmp".equalsIgnoreCase(fileExtension)) {
			return "image/bmp";
		}
		if (".gif".equalsIgnoreCase(fileExtension)) {
			return "image/gif";
		}
		if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
				|| ".png".equalsIgnoreCase(fileExtension)) {
			return "image/jpeg";
		}
		if (".html".equalsIgnoreCase(fileExtension)) {
			return "text/html";
		}
		if (".txt".equalsIgnoreCase(fileExtension)) {
			return "text/plain";
		}
		if (".vsd".equalsIgnoreCase(fileExtension)) {
			return "application/vnd.visio";
		}
		if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
			return "application/vnd.ms-powerpoint";
		}
		if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
			return "application/msword";
		}
		if (".xml".equalsIgnoreCase(fileExtension)) {
			return "text/xml";
		}
		// 默认返回类型
		return "image/jpeg";
	}

	/**
	 * 根据key获取url
	 */
	public String urlFromFileKey(String bucket, String folder, String fileName) {
		if(!StringUtils.isBlank(adminProperties.getOss().getDomain())) {
			return adminProperties.getOss().getDomain() + "/" + folder + fileName;
		}
		return "https://" + bucket + "." + adminProperties.getOss().getEndPoint() + "/" + folder + fileName;
	}

	/**
	 * 创建存储空间Bucket
	 */
	public String createBucket(String bucket) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		// 存储空间
		if (!ossClient.doesBucketExist(bucket)) {
			// 创建存储空间
			CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucket);
			// 设置bucket权限为公共读，默认是私有读写
			createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
			// 设置bucket存储类型为低频访问类型，默认是标准类型
			createBucketRequest.setStorageClass(StorageClass.IA);
			ossClient.createBucket(createBucketRequest);
			log.debug("创建" + bucket + "Bucket成功！");
		}

		// 关闭client
		ossClient.shutdown();
		return bucket;
	}

	/**
	 * 删除存储空间
	 */
	public void deleteBucket(String bucket) throws Exception {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		try {
			ossClient.deleteBucket(bucket);
			log.debug("删除" + bucket + "Bucket成功！");
		} catch (Exception e) {
			log.debug("删除" + bucket + "Bucket失败：" + e.getMessage());
			throw new Exception(e.getMessage());
		} finally {
			ossClient.shutdown();
		}
	}

	/**
	 * 创建文件夹
	 */
	public String createFolder(String bucket, String folder) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		// 判断文件夹是否存在，不存在则创建
		if (!ossClient.doesObjectExist(bucket, folder)) {
			// 创建文件夹
			ossClient.putObject(bucket, folder, new ByteArrayInputStream(new byte[0]));
			log.debug("创建" + folder + "Folder成功！");
		}

		ossClient.shutdown();
		return folder;
	}

	/**
	 * 删除文件夹
	 */
	public void deleteFolder(String bucket, String folder) throws Exception {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		// 判断文件夹是否存在，不存在则创建
		if (ossClient.doesObjectExist(bucket, folder)) {
			try {
				ossClient.deleteObject(bucket, folder);
				log.debug("删除" + folder + "Folder成功！");
			} catch (Exception e) {
				log.debug("删除" + folder + "Folder失败：" + e.getMessage());
				throw new Exception(e.getMessage());
			} finally {
				ossClient.shutdown();
			}
		}

	}

	/**
	 * 下载文件到本地
	 */
	public String getObject(String bucket, String folder, String fileName, String localPath) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		String localFileKey = localPath + folder + fileName;
		ossClient.getObject(new GetObjectRequest(bucket, folder + fileName), new File(localFileKey));
		log.debug("从OSS下载文件成功！", localFileKey);

		ossClient.shutdown();
		return localFileKey;
	}

	/**
	 * 删除存储对象
	 */
	public void deleteObject(String bucket, String folder, String fileName) throws Exception {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		try {
			ossClient.deleteObject(bucket, folder + fileName);
			log.debug("删除" + bucket + "下的文件" + folder + fileName + "成功！");
		} catch (Exception e) {
			log.debug("删除" + bucket + "下的文件" + folder + fileName + "失败：" + e.getMessage());
			throw new Exception(e.getMessage());
		} finally {
			ossClient.shutdown();
		}
	}

	/**
	 * 检查文件是否存在
	 */
	public boolean checkObject(String bucket, String folder, String fileName) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		boolean ok = ossClient.doesObjectExist(bucket, folder + fileName);

		ossClient.shutdown();
		return ok;
	}

	/**
	 * 上传文件
	 */
	public String upload(String bucket, String folder, MultipartFile file) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		try {
			// 以输入流的形式上传文件
			InputStream is = file.getInputStream();
			// 文件名
			String fileName = DateUtil.getCurrentTimestamp() + file.getOriginalFilename();
			// 文件大小
			Long fileSize = file.getSize();
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 上传的文件的长度
			metadata.setContentLength(is.available());
			// 指定该Object被下载时的网页的缓存行为
			metadata.setCacheControl("no-cache");
			// 指定该Object下设置Header
			metadata.setHeader("Pragma", "no-cache");
			// 指定该Object被下载时的内容编码格式
			metadata.setContentEncoding("utf-8");
			// 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
			// 如果没有扩展名则填默认值application/octet-stream
			metadata.setContentType(getContentType(fileName));
			// 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
			metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
			// 上传文件 (上传文件流的形式)
			ossClient.putObject(bucket, folder + fileName, is, metadata);

			return urlFromFileKey(bucket, folder, fileName);
		} catch (Exception e) {
			log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
			return null;
		} finally {
			ossClient.shutdown();
		}
	}

	/**
	 * 上传文件
	 */
	public String upload(String bucket, String folder, File file) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		try {
			// 以输入流的形式上传文件
			InputStream is = new FileInputStream(file);
			// 文件名
			String fileName = DateUtil.getCurrentTimestamp() + file.getName();
			// 文件大小
			Long fileSize = file.length();
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 上传的文件的长度
			metadata.setContentLength(is.available());
			// 指定该Object被下载时的网页的缓存行为
			metadata.setCacheControl("no-cache");
			// 指定该Object下设置Header
			metadata.setHeader("Pragma", "no-cache");
			// 指定该Object被下载时的内容编码格式
			metadata.setContentEncoding("utf-8");
			// 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
			// 如果没有扩展名则填默认值application/octet-stream
			metadata.setContentType(getContentType(fileName));
			// 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
			metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
			// 上传文件 (上传文件流的形式)
			ossClient.putObject(bucket, folder + fileName, is, metadata);
			// 重命名文件
			// 解析结果
			return urlFromFileKey(bucket, folder, fileName);
		} catch (Exception e) {
			log.error("上传阿里云OSS服务器异常." + e.getMessage());
			return null;
		} finally {
			ossClient.shutdown();
		}
	}
	
	/**
	 * 上传文件
	 */
	public String upload(String bucket, String folder, String fileName, byte[] data) {
		OSSClient ossClient = new OSSClient(adminProperties.getOss().getEndPoint(),
				adminProperties.getOss().getAccessKeyId(), adminProperties.getOss().getAccessKeySecret());

		try {
			// 文件大小
			int fileSize = data.length;
			InputStream is = new ByteArrayInputStream(data);
			// 重命名文件
			fileName = DateUtil.getCurrentTimestamp() + fileName;
			// 创建上传Object的Metadata
			ObjectMetadata metadata = new ObjectMetadata();
			// 上传的文件的长度
			metadata.setContentLength(data.length);
			// 指定该Object被下载时的网页的缓存行为
			metadata.setCacheControl("no-cache");
			// 指定该Object下设置Header
			metadata.setHeader("Pragma", "no-cache");
			// 指定该Object被下载时的内容编码格式
			metadata.setContentEncoding("utf-8");
			// 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
			// 如果没有扩展名则填默认值application/octet-stream
			metadata.setContentType(getContentType(fileName));
			// 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
			metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
			// 上传文件 (上传文件流的形式)
			ossClient.putObject(bucket, folder + fileName, is, metadata);
			// 解析结果
			return urlFromFileKey(bucket, folder, fileName);
		} catch (Exception e) {
			log.error("上传阿里云OSS服务器异常." + e.getMessage());
			return null;
		} finally {
			ossClient.shutdown();
		}
		
	}

}